package com.kitty.mina.codec;


import com.kitty.mina.message.Message;
import com.kitty.mina.session.SessionProperties;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import javax.script.ScriptException;
import lombok.extern.slf4j.Slf4j;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//后加
import com.kitty.mina.codec.CodecContext;
import com.kitty.mina.codec.IMessageEncoder;
import com.kitty.mina.codec.MinaEncoder;
import com.kitty.mina.codec.SerializerHelper;
import com.kitty.mina.codec.StanUtils;



/**
 * 2.5 新版本encoder
 *
 * @author StanWind
 * @create 2020 - 05 - 21 12:15 AM
 */
@Slf4j
public class WDEncoder implements ProtocolEncoder {


    static String content = "[49159, 41051, 41106, 45277, 41009, 4099, 65527, 65511, 21137, 65525, 65507, 32747, 12023, 36889, 4163, 8425, 12016, 65505, 65529, 61671, 65531, 61677, 45074, 61589, 45193, 61543, 53257, 4321, 61553, 33055, 32855, 62209, 9129, 32825, 20993, 53417, 32811, 45154, 45388, 45239, 45219, 45217, 45319, 53399, 61663, 53447, 41484, 20480, 4275, 16383]";

    @Override
    public void dispose(IoSession arg0) throws Exception {

    }

    @Override
    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
        CodecContext context = (CodecContext) session.getAttribute(SessionProperties.CODEC_CONTEXT);
        if (context == null) {
            context = new CodecContext();
            session.setAttribute(SessionProperties.CODEC_CONTEXT, context);
        }
        IoBuffer buffer = writeMessage((Message) message);
        out.write(buffer);
    }

    private IoBuffer writeMessage(Message message) {
        //选线包不加密发送
        if (message.getModule() == 0xB1F3 || message.getModule() == 0x3357) {
            return MinaEncoder.writeMessage(message);
        } else {
            return encryptMsg(message);
        }
    }

    public static IoBuffer encryptMsg(Message message) {
        //无符号 加密key
        int randomKey = ThreadLocalRandom.current().nextInt(0x0FFF) + 1;
        int moduleId = message.getModule();
        IoBuffer buffer = IoBuffer.allocate(32).setAutoExpand(true).setAutoShrink(true);
//        buffer.putUnsignedInt(1297743872);
        buffer.putUnsignedShort(0x4D5A);
        buffer.putUnsignedShort(randomKey);
        buffer.putUnsignedInt(0);
        //写入具体消息的内容
        IMessageEncoder msgEncoder = SerializerHelper.getInstance().getEncoder();

        byte[] body = msgEncoder.writeMessageBody(message);
//        if (content.contains(moduleId+"")){
//            List<Integer> list = Json.fromJsonAsList(Integer.class,content);
//            list.remove(new Integer(moduleId));
//            content = Json.toJson(list, JsonFormat.compact());
//            logger.error("未返回协议=={}=={}",content);
//            logger.error("未返回协议=={}=={}",list.size());
//        }
//        print(moduleId,body);
        // 包体长度
        int posi = 0;
//        if (moduleId == 64977) {
//            posi = body.length + 4;
//        } else {
            posi = body.length + 2;
//        }

        ////////重写部分
        //var a1 = Bytes2Hex(buff.slice(0, 2));
        int a1 = moduleId;
        //俩short HEX拼接
        //var a2 = Bytes2Hex(header.slice(2, 4)) + Bytes2Hex(header.slice(8, 10));
        int a2 = randomKey << 16 | posi;
        //var m = gfParseM(a1, a2);
        int m = gfParseM(a1, a2);
        //buff[0] = m >>> 8;
        //buff[1] = m & 0x00FF;
        moduleId = (m >>> 8) << 8 | m & 0x00FF;
        //var k = Hex2Bytes(gfParseK(a2));
        byte[] k = StanUtils.unsignedIntToByte4(gfParseK(a2));
        //var v6 = parseInt(Bytes2Hex(header.slice(8, 10)), 16);
        int v6 = posi;
        int v9 = (v6 - 2) & 0xFFFF;
        int v11 = v9 & 0xFFFFFFFC;
        //////////////////

        buffer.putShort((short) posi);
        buffer.putUnsignedShort(moduleId);
//        if (moduleId == 64977) {
//            //buffer.putShort((short) ((short) body.length + 2));
//            byte[] newBody = new byte[body.length + 2];
//            byte[] len = StanUtils.unsignedShortToByte2(body.length + 2);
//            //拷贝长度
//            System.arraycopy(len, 0, newBody, 0, 2);
//            //拷贝包体
//            System.arraycopy(body, 0, newBody, 2, body.length);
//            body = newBody;
//        }

        if ((v9 & 0xFFFFFFFC) != 0) {
            for (int i = 0; i < v11; i++) {
                if (i >= body.length) {
                    log.error("encryp1 random:{} cmd:{} v9:{}, v11:{}, body len: {}, k len: {}", randomKey, moduleId, v9, v11, body.length, k.length);
                    return jsEncrypt(message);
                    //break;
                }
                body[i] = (byte) (body[i] ^ k[i % 4]);
            }
        }
        if (v9 > v11) {
            do {
                if (v11 >= body.length) {
                    log.error("encryp2 random:{} cmd:{} v9:{}, v11:{}, body len: {}",randomKey, moduleId, v9, v11, body.length);
                    return jsEncrypt(message);
                }
                body[v11] = (byte) (body[v11] ^ v11);
                v11++;
            } while (v9 != v11);
        }

        buffer.put(body);
        buffer.flip();
        buffer.rewind();
//        log.error("moduleId=={}=={}=={}",message.getModule(),buffer.getHexDump(),body.length);
        return buffer;
    }

    private static void print(int moduleId,byte[] body){
        int posi = 0;
        if (moduleId == 64977) {
            posi = body.length + 4;
        } else {
            posi = body.length + 2;
        }
        IoBuffer buffer = IoBuffer.allocate(32).setAutoExpand(true).setAutoShrink(true);
        buffer.putUnsignedInt(1297743872);
        buffer.putUnsignedInt(0);
        buffer.putShort((short) posi);
        buffer.putUnsignedShort(moduleId);
        if (moduleId == 64977) {
            buffer.putShort((short) ((short) body.length + 2));
        }
        buffer.put(body);
        buffer.flip();
        buffer.rewind();
        if (16383 != moduleId && 4275 != moduleId){
            log.error("返回解析协议:==={}=={}", moduleId, buffer.getHexDump());
        }
    }


    public static int gfParseM(int a1, int a2) {
        return (((((a2 & 0x00FF0000) >>> 0x10) ^ (a2 & 0xFF) ^ ((a1 & 0x0000FF00) >>> 8)) << 0x8) | ((a1 & 0x000000FF)
                ^ (a2 & 0xFF)));
    }

    public static long gfParseK(int a1) {
        return (((((((((((a1 & 0x00FF0000) >>> 0x10) | ((a1 & 0x000000FF))) << 0x8) | (a1 >>> 0x18)) | ((a1
                & 0x000000FF))) << 0x8) | (a1 >>> 0x18)) | ((a1 & 0x00FF0000) >>> 0x10)) << 0x8) | ((a1 >>> 0x18) ^ (
                (a1 & 0x00FF0000) >>> 0x10))) >>> 0;
    }

    public static void main(String[] args) {
        //无符号 加密key
        int randomKey = 0x0000;//ThreadLocalRandom.current().nextInt(0xFFFF) + 1;
        int moduleId = 0xFDD1;
        String bodyHex = "02D8FFE30001031605C90400010001007C00010404BAA3B9EA000603000019C6000B0300000B90001F02001D006D01020010020000002C020003001102000000280717EE0029078000000202001D0009020071000502001D000D020039000703000019C6000C0300000B9000030300000143000A0300000ABE000E0200C50008030000056E003F030000000900190300000000004102000E0032020000003302000000340200000035020000003602000000380200000039020000003A020000003B020000003C020000003D03000027830040030000000D003E0300000064004203000000640037030001E2A600560717EE006802005A006902002A006B02FFF7006C02002D006A02002D006E0200000105020000010F020000010602000000790300000000007A030000000001090300000000010A03000000000126010002CF030000000002D0030000000003200300000000032103000000000322020000032302000003240200000325020000032602000002D102000002D202000002D302000002D402000002D502000002D602000001370100010E030000000000CD061403660100036703000000000368030000000003A3010003A4030000000003A5030000000003A70100036F040000E802003200E902000200EB02000500EC02FFCF00ED020005013B020000013C020000013D020000013E020000013F0200000140020000014102000001420200000143020000014402000001450200000146020000014702000001480200000149020000037303000000000374030000000003750100037803000000000376010003770300000000037A020000037B020000037C01000BC803000000000BC903000000000BCC03000000000BCD03000000000BCA03000000000BCB03000000000398030000014303990300000ABE039A030000056E039B030000000901320409333639343737383932010B0404BAA3B9EA00B00404B9FEB9FE01D2030000000001D30300000000015B0100";
        //开始


        IoBuffer buffer = IoBuffer.allocate(32).setAutoExpand(true).setAutoShrink(true);
//        buffer.putUnsignedInt(1297743872);
        buffer.putUnsignedShort(0x4D5A);
        buffer.putUnsignedShort(randomKey);
        buffer.putUnsignedInt(0);

        byte[] body = StanUtils.hexToByteArray(bodyHex);
        log.error(String.format("0x%x" , body.length));
        // 包体长度
        int posi = 0;

        posi = body.length + 2;

        ////////重写部分
        //var a1 = Bytes2Hex(buff.slice(0, 2));
        int a1 = moduleId;
        //俩short HEX拼接
        //var a2 = Bytes2Hex(header.slice(2, 4)) + Bytes2Hex(header.slice(8, 10));
        int a2 = randomKey << 16 | posi;
        //var m = gfParseM(a1, a2);
        int m = gfParseM(a1, a2);
        //buff[0] = m >>> 8;
        //buff[1] = m & 0x00FF;
        moduleId = (m >>> 8) << 8 | m & 0x00FF;
        //var k = Hex2Bytes(gfParseK(a2));
        byte[] k = StanUtils.unsignedIntToByte4(gfParseK(a2));
        //var v6 = parseInt(Bytes2Hex(header.slice(8, 10)), 16);
        int v6 = posi;
        int v9 = (v6 - 2) & 0xFFFF;
        int v11 = v9 & 0xFFFFFFFC;
        //////////////////

        buffer.putShort((short) posi);
        buffer.putUnsignedShort(moduleId);


        if ((v9 & 0xFFFFFFFC) != 0) {
            for (int i = 0; i < v11; i++) {
                if (i >= body.length) {
                    log.error("encryp1 random:{} cmd:{} v9:{}, v11:{}, body len: {}, k len: {}", randomKey, moduleId, v9, v11, body.length, k.length);
//                    return jsEncrypt(message);
                    break;
                }
                body[i] = (byte) (body[i] ^ k[i % 4]);
            }
        }
        if (v9 > v11) {
            do {
                if (v11 >= body.length) {
                    log.error("encryp2 random:{} cmd:{} v9:{}, v11:{}, body len: {}",randomKey, moduleId, v9, v11, body.length);
//                    return jsEncrypt(message);
                    break;
                }
                body[v11] = (byte) (body[v11] ^ v11);
                v11++;
            } while (v9 != v11);
        }

        buffer.put(body);
        buffer.flip();
        buffer.rewind();


        //4D5AB27700000000006E26913FFF7FFCF7C57FFFF161A9391E1588FEE30FAA334A70A34E0B7FBC2D2664DC3E4300D14B339BCF4576C57FF24A66CA3E447BAF3AC6F4B021F7C47FFE083A7FFEF7C57FFEF7C5A2DED3127FFDF6F47BEAC2803EC7B5F43AC9C68048BCB2F74FCDB3F639C7F7DA7DFEBFC557F9EC9F
        jsEncrypt("4D5A00000000000002DAFDD102D8FFE30001031605C90400010001007C00010404BAA3B9EA000603000019C6000B0300000B90001F02001D006D01020010020000002C020003001102000000280717EE0029078000000202001D0009020071000502001D000D020039000703000019C6000C0300000B9000030300000143000A0300000ABE000E0200C50008030000056E003F030000000900190300000000004102000E0032020000003302000000340200000035020000003602000000380200000039020000003A020000003B020000003C020000003D03000027830040030000000D003E0300000064004203000000640037030001E2A600560717EE006802005A006902002A006B02FFF7006C02002D006A02002D006E0200000105020000010F020000010602000000790300000000007A030000000001090300000000010A03000000000126010002CF030000000002D0030000000003200300000000032103000000000322020000032302000003240200000325020000032602000002D102000002D202000002D302000002D402000002D502000002D602000001370100010E030000000000CD061403660100036703000000000368030000000003A3010003A4030000000003A5030000000003A70100036F040000E802003200E902000200EB02000500EC02FFCF00ED020005013B020000013C020000013D020000013E020000013F0200000140020000014102000001420200000143020000014402000001450200000146020000014702000001480200000149020000037303000000000374030000000003750100037803000000000376010003770300000000037A020000037B020000037C01000BC803000000000BC903000000000BCC03000000000BCD03000000000BCA03000000000BCB03000000000398030000014303990300000ABE039A030000056E039B030000000901320409333639343737383932010B0404BAA3B9EA00B00404B9FEB9FE01D2030000000001D30300000000015B0100");
        //结束
        byte[] enres = StanUtils.ioBufferToByte(buffer);
        System.out.println(StanUtils.bytesToHex(enres));
    }

    public static IoBuffer jsEncrypt(Message message) {
        String hex = StanUtils.bytesToHex(StanUtils.ioBufferToByte(MinaEncoder.writeMessage(message)));

        return jsEncrypt(hex);
    }

    public static IoBuffer jsEncrypt(String hex) {
        try {
            log.error("js origin {}", hex);
            hex = StanUtils.decrypt(hex.replaceAll(" ", ""));
        } catch (Exception e) {
            log.error("js加密失败", e);
        }
        log.error("js生成 {}", hex.toUpperCase());
        byte[] bb = StanUtils.hexToByteArray(hex);
        IoBuffer tb = IoBuffer.allocate(32).setAutoExpand(true).setAutoShrink(true);
        tb.put(bb);
        tb.flip();
        tb.rewind();

        return tb;
    }
}
